package com.common.auth.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.common.api.enums.EnableStateEnum;
import com.common.api.exception.CommonException;
import com.common.auth.api.dto.OrganizationDto;
import com.common.auth.api.service.OrganizationService;
import com.common.auth.api.service.UserService;
import com.common.auth.dao.OrganizationMapper;
import com.common.auth.dao.UserMapper;
import com.common.auth.error.AuthorError;
import com.common.auth.po.OrganizationPo;
import com.common.auth.po.UserPo;
import com.common.util.GenerateSequenceUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 组织机构表服务实现类
 * </p>
 *
 * @author system
 */
@Slf4j
@Service
public class OrganizationServiceImpl extends OrganizationService {
	

	@Autowired
	private OrganizationMapper organizationMapper;

	@Autowired
	private UserService userService;

	@Autowired
	private UserMapper userMapper;


	@Transactional(rollbackFor = {Exception.class})
	@Override
	public void deleteOrgById(String orgId) {
		// 日志记录方法调用
		log.info("开始删除机构, 机构id为：" + orgId);
		try {
			// 校验组织机构ID是否为空
			validateOrgId(orgId);
			// 检查组织是否存在
			OrganizationPo organizationPo = getOrganizationPoById(orgId);
			// 检查是否有子节点
			checkAndThrowIfSubNodesExist(organizationPo.getOrganizationCode());
			// 将使用这个机构的用户的相关机构信息清空
			checkAndUpdateIfUserExist(organizationPo.getOrganizationCode());
			// 直接删除
			organizationMapper.deleteById(orgId);
			log.info("成功删除组织机构, 机构id为：" + orgId);
		} catch (Exception e) {
			log.error("删除机构出现异常, {}", e.getMessage());;
			throw e;
		}
	}

	/**
	 * 删除组织机构后，
	 * 检查这个组织机构都有哪些用户使用，
	 * 然后将用户表里的机构编码信息置空
	 * @param organizationCode
	 *
	 *
	*/
	private void checkAndUpdateIfUserExist(String organizationCode) {
		if (StringUtils.isBlank(organizationCode)) {
			log.error("组织机构代码无效！");
			throw new CommonException("组织机构代码不能为空！");
		}
		List<UserPo> usersToBeUpdated = userService.list(Wrappers.lambdaQuery(UserPo.class)
				.eq(UserPo::getOrganizationCode, organizationCode));
		if (CollectionUtils.isNotEmpty(usersToBeUpdated)) {
			boolean updated = batchUpdateOrganizationCode(usersToBeUpdated);
			if (!updated) {
				log.error("更新用户机构信息出现异常！");
				throw new CommonException("更新用户机构信息出现异常！");
			}
		}
	}


	public boolean batchUpdateOrganizationCode(List<UserPo> userList) {
		if (CollectionUtils.isEmpty(userList)) {
			return true; // 如果集合为空，直接返回成功
		}
		List<String> collectIds = userList.stream()
				.map(UserPo::getId)
				.collect(Collectors.toList());
		try {
			int rowsAffected = userMapper.update(null, Wrappers.lambdaUpdate(UserPo.class)
					.in(UserPo::getId, collectIds)
					.set(UserPo::getOrganizationCode, null));
			if (rowsAffected <= 0) {
				log.error("更新用户[{}]的机构信息失败", collectIds);
			}
		} catch (Exception e) {
			log.error("更新用户[{}]的机构信息异常", collectIds);
			throw e;
		}
		return true;
	}


	private void validateOrgId(String orgId) {
		if (StringUtils.isBlank(orgId)) {
			throw new CommonException("请选择要删除的机构！");
		}
	}

	private OrganizationPo getOrganizationPoById(String orgId) {
		return Optional.ofNullable(organizationMapper.selectById(orgId)).orElseThrow(
				() -> {
					log.info("当前要删除的机构不存在, 机构id为：" + orgId);
					return new CommonException("当前要删除的机构不存在！");
                }
		);
	}

	private void checkAndThrowIfSubNodesExist(String organizationCode) {
		log.info("检查当前要删除的机构 {} 是否存在下级机构...", organizationCode);
		if (organizationMapper.exists(Wrappers.lambdaQuery(OrganizationPo.class)
				.eq(OrganizationPo::getParentCode, organizationCode))) {
			log.info("当前要删除的机构存在下级机构，请先删除下级机构！");
			throw new CommonException(AuthorError.orgSubNodeExist);
		}
	}


	@Transactional(rollbackFor = Exception.class)
	@Override
	public int add(OrganizationDto dto) {
		try {
			validateAndAddOrgInfo(dto);
			return 1;
		} catch (Exception e) {
			log.error("添加机构过程中出现异常: {}", e.getMessage());
			throw e;
		}
	}


	private void validateAndAddOrgInfo(OrganizationDto dto) {
		// 校验参数
		validateOrgInfo(dto);
		// 每次新增组织机构的时候校验组织机构账号是否唯一
		checkOrgCodeUnique(dto.getOrganizationCode());
		// 设置默认启用状态
		setDefaultEnableFlag(dto);
		prepareOrgInfo(dto);
		organizationMapper.insert(dto);
	}

	private void validateOrgInfo(OrganizationDto dto) {
		if (Objects.isNull(dto)) {
			throw new CommonException("机构信息不能为空！");
		}
		validateField(dto.getOrganizationCode(), "机构编码");
		validateField(dto.getOrganizationName(), "机构名称");
	}

	private void validateField(String value, String filedName) {
		if (StringUtils.isBlank(value)) {
			throw new CommonException(filedName + "不能为空！");
		}
	}


	private void checkOrgCodeUnique(String organizationCode) {
		if (organizationMapper.exists(Wrappers.lambdaQuery(OrganizationPo.class)
				.eq(OrganizationPo::getOrganizationCode, organizationCode))) {
			throw new CommonException("组织机构编码不能重复！");
		}
	}

	private void setDefaultEnableFlag(OrganizationDto dto) {
		if(StringUtils.isEmpty(dto.getEnableStateEnum())) {
			dto.setEnableStateEnum(EnableStateEnum.enable.getEunmCode());
		}else {
			dto.setEnableStateEnum(dto.getEnableStateEnum());
		}
	}

	private void prepareOrgInfo(OrganizationDto dto) {
		if (StringUtils.isBlank(dto.getId())) {
			// 新增组织机构的时候生成组织机构的ID
			dto.setId(GenerateSequenceUtil.generateSequenceNo());
			dto.setCreateTime(new Date());
			dto.setUpdateTime(new Date());
		} else {
			// 更新操作
			dto.setUpdateTime(new Date());
		}
	}


	@Transactional(rollbackFor = Exception.class)
	@Override
	public int modify(OrganizationDto dto) {
		try {
			validateAndModifyOrgInfo(dto);
			return 1;
		} catch (Exception e) {
			log.error("修改机构过程中出现异常: {}", e.getMessage());
			throw e;
		}
	}


	private void validateAndModifyOrgInfo(OrganizationDto dto) {
		// 校验参数
		validateOrgInfo(dto);
		// 设置默认启用标志
		setDefaultEnableFlag(dto);
		// 校验机构是否已经存在
		OrganizationPo organizationPo = checkOrgInfoExistence(dto);
		// 机构编码不允许修改
		checkOrgCodeModification(dto, organizationPo);
		// 修改组织机构信息
		prepareOrgInfo(dto);
		organizationMapper.updateById(dto);
	}

	private OrganizationPo checkOrgInfoExistence(OrganizationDto dto) {
		return Optional.ofNullable(organizationMapper.selectById(dto.getId()))
				.orElseThrow(() -> new CommonException("当前要修改的组织机构信息不存在！"));
	}

	private void checkOrgCodeModification(OrganizationDto dto, OrganizationPo organizationPo) {
		checkFieldModification(organizationPo.getOrganizationCode(), dto.getOrganizationCode(), "机构编码");
	}

	private void checkFieldModification(String oldValue, String newValue, String errorMessage) {
		if (!Objects.equals(oldValue, newValue)) {
			throw new CommonException(errorMessage + "不允许修改");
		}
	}


	/**
	 * 查询组织机构树
	 * @return
	 */
	@Override
	public List<OrganizationDto> queryOrgTreeList() {
		List<OrganizationPo> organizationPoList = list(Wrappers.lambdaQuery(OrganizationPo.class));
		List<OrganizationDto> rootList = buildResourceTress(organizationPoList);
		return rootList;
	}


	private List<OrganizationDto> buildResourceTress(List<OrganizationPo> organizationPoList){
		List<OrganizationDto> rootList=new ArrayList<>();
		Map<String,List<OrganizationDto>> parentMap=new HashMap<>();
		organizationPoList.forEach(item->{
			OrganizationDto organizationDto = convert(item, OrganizationDto.class);
			organizationDto.setChildren(new ArrayList<>());
			String parentCode = item.getParentCode();
			if(StringUtils.isEmpty(parentCode)) {
				rootList.add(organizationDto);
			}else {
				List<OrganizationDto> subList = parentMap.get(parentCode);
				if(subList == null) {
					subList = new ArrayList<>();
					parentMap.put(parentCode, subList);
				}
				subList.add(organizationDto);
			}
		});
		// 生成子节点数据
		rootList.forEach(organizationDto ->{
			addSubList(organizationDto,parentMap);
		});
		return rootList;
	}


	// 循环调用生成子节点数据
	private void addSubList(OrganizationDto parentDto, Map<String, List<OrganizationDto>> parentMap) {
		String parentCode = parentDto.getOrganizationCode();
		List<OrganizationDto> subList = parentMap.get(parentCode);
		if(CollectionUtils.isEmpty(subList)) {
			return;
		}
		parentDto.getChildren().addAll(subList);
		subList.forEach(subItem->{
			addSubList(subItem,parentMap);
		});
	}

	@Override
	public List<String> getSearchKeyList() {
		return Arrays.asList("organization_code","organization_name");
	}

}
